/*--------------------------------------------------------------------------------*/
#ifndef __GRAPHIC_TEXT__
#define __GRAPHIC_TEXT__
/*--------------------------------------------------------------------------------*/
#include "primitives.h"
#include "object.h"
#include "util.h"
#include "graphic_font.h"
#include "array.h"
#include "graphic_vertex_buffer.h"
#include "color.h"
#include "math_vector_3.h"
#include "defs.h"
#include "primitives.h"
#include "graphic_2d_object.h"
#include "math_angle.h"
/*--------------------------------------------------------------------------------*/
class GRAPHIC_TEXT : public GRAPHIC_2D_OBJECT
{
	friend class GRAPHIC_TEXT_CONTAINER;

	// -- PUBLIC

public:

    DECLARE_REF( GRAPHIC_TEXT );

    // .. CONSTRUCTORS

    GRAPHIC_TEXT() :
    	GRAPHIC_2D_OBJECT(),
    	Text(),
    	Font(),
    	Color( COLOR::ColorWhite ),
    	Width( 0 ),
    	Height( 0 ),
    	CharacterSpacing( 0.0f ),
    	ItHasChanged( false ),
    	ExtentPerChar( MATH_VECTOR_2::Zero )
    {

    }

    virtual ~GRAPHIC_TEXT()
    {
     
    }

    // .. METHODS

    virtual VOID Update( const TIMER & /*timer*/ )
    {
    	if( ItHasChanged )
    	{
    		GenerateMesh();
    	}
    }

    virtual VOID Render()
    {
    	Font->BindTexture();
    	OPENGL_Color( Color );
    	OPENGL_PushMatrix();
    	OPENGL_TranslateXY( Position.X, Position.Y );
    	OPENGL_RotateZ( Angle * 180.0f / MATH_ANGLE_Pi );
    	GRAPHIC_VERTEX_BUFFER::EnableVertexArray( ( REAL * ) VertexTable.GetArray(), 2, sizeof( VERTEX ) );
    	GRAPHIC_VERTEX_BUFFER::EnableTexCoordArray( ( REAL * ) & VertexTable[0].UV , 2, sizeof( VERTEX ) );
    	GRAPHIC_VERTEX_BUFFER::Draw( VertexTable.GetItemCount() );
    	DEBUG_CheckOpenGL();
    	OPENGL_PopMatrix();
    }

    VOID SetPosition( const MATH_VECTOR_2 & position )
    {
    	Position = position;
    	ItHasChanged = true;
    }

    VOID SetExtent( const MATH_VECTOR_2 & extent )
    {
    	Extent = extent;
    	ItHasChanged = true;
    }

    VOID SetExtentPerChar( const MATH_VECTOR_2 & extent )
	{
		ExtentPerChar = extent;
		ItHasChanged = true;
	}


    VOID SetText( const TEXT & text )
    {
    	Text = text;
    	ItHasChanged = true;
    }

    VOID SetFont( const GRAPHIC_FONT & font )
    {
    	Font = font;
    	ItHasChanged = true;
    }

    VOID SetColor( const COLOR & color )
    {
    	Color = color;
    }

    VOID SetCharacterSpacing( const REAL spacing )
    {
    	CharacterSpacing = spacing;
    	ItHasChanged = true;
    }

    const TEXT & GetText() const
    {
    	return Text;
    }

    // -- PROTECTED

protected :

    // .. METHODS

    VOID GenerateMesh( const MATH_VECTOR_2 & offset = MATH_VECTOR_2::Zero )
    {
    	INDEX
			char_index;
    	MATH_VECTOR_2
			position_offset,
			char_position_offset;
    	REAL
			char_size_x,
			char_size_y;
    	REAL
			spacing;

    	DEBUG_Require( !Font.IsNull() );

    	Width = Text.GetLength();
    	Height = 1;

    	if( !ExtentPerChar.IsZero() )
    	{
    		char_size_x = ExtentPerChar.X;
    		char_size_y = ExtentPerChar.Y;

    		Extent.Set( char_size_x * Width, char_size_y * Height );
    	}
    	else
    	{
    		char_size_x = Extent.X / Width;
    		char_size_y = Extent.Y / Height;
    	}


    	spacing = CharacterSpacing > 0.0f ? CharacterSpacing : char_size_x;

    	VertexCount = Width * 6;

    	VertexTable.SetItemCount( VertexCount );

    	position_offset =  Extent * -0.5f + offset;

    	for_each_index( char_index, Text.GetLength() )
    	{
        	const GRAPHIC_TEXTURE_SET::UV_COORD
    			& coord = Font->GetUVCoord( Text[ char_index ] );

    		char_position_offset = MATH_VECTOR_2( spacing * char_index, 0 );

    		// Triangle 1
    		VertexTable[ char_index * 6 + 0 ].Position = position_offset + char_position_offset + MATH_VECTOR_2( 0, char_size_y );
    		VertexTable[ char_index * 6 + 1 ].Position = position_offset + char_position_offset + MATH_VECTOR_2( char_size_x , char_size_y );
    		VertexTable[ char_index * 6 + 2 ].Position = position_offset + char_position_offset + MATH_VECTOR_2( char_size_x , 0 );
    		VertexTable[ char_index * 6 + 0 ].UV.Set( coord.Start.X, coord.End.Y );
    		VertexTable[ char_index * 6 + 1 ].UV.Set( coord.End.X, coord.End.Y );
    		VertexTable[ char_index * 6 + 2 ].UV.Set( coord.End.X, coord.Start.Y );

    		// Triangle 2
    		VertexTable[ char_index * 6 + 3 ].Position = VertexTable[ char_index * 6 + 2 ].Position;
    		VertexTable[ char_index * 6 + 4 ].Position = position_offset + char_position_offset;
    		VertexTable[ char_index * 6 + 5 ].Position = VertexTable[ char_index * 6 + 0 ].Position;
    		VertexTable[ char_index * 6 + 3 ].UV = VertexTable[ char_index * 6 + 2 ].UV;
    		VertexTable[ char_index * 6 + 4 ].UV.Set( coord.Start.X, coord.Start.Y );
    		VertexTable[ char_index * 6 + 5 ].UV = VertexTable[ char_index * 6 + 0 ].UV;
    	}
    }

    // .. ATTRIBUTES

    COUNT
		VertexCount;
    TEXT
		Text;
    GRAPHIC_FONT::REF
		Font;
    COLOR
		Color;
    COUNT
		Width,
		Height;
    REAL
		CharacterSpacing;
    BOOL
    	ItHasChanged;
    MATH_VECTOR_2
    	ExtentPerChar;
    
};
/*--------------------------------------------------------------------------------*/
#endif
